package com.bk.ui.controller;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;

import org.hashids.Hashids;
import org.joda.time.DateTime;

import com.bk.controller.BKController;
import com.bk.interceptor.BKInterceptor;
import com.bk.utils.AES;
import com.bk.utils.PayUtils;
import com.cjw.model.DBMap;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.jfinal.weixin.sdk.api.PaymentApi;
import com.jfinal.weixin.sdk.api.PaymentApi.TradeType;
import com.jfinal.weixin.sdk.kit.IpKit;
import com.jfinal.weixin.sdk.kit.PaymentKit;
import com.moomi.common.model.BkAdv;
import com.moomi.common.model.BkApp;
import com.moomi.common.model.BkBooking;
import com.moomi.common.model.BkItem;
import com.moomi.common.model.BkOrder;
import com.moomi.common.model.BkSelection;
import com.moomi.common.model.BkShop;
import com.moomi.common.model.BkWechat;
import com.utils.AuthUtils;
import com.utils.DateUtils;
import com.utils.Utils;
import com.utils.interceptor.TestInterceptor;
import com.zhenyi.core.wechat.bridge.WXThirdUtils;

import booking.utils.BookingUtils;
import cn.hutool.json.JSONObject;

/**
 * 预约的首页
 * 
 * @author cen
 *
 */
@Clear
public class BKIndexController extends BKController {

	// private final String SECRET = "9cdf453183a36f6e0eb0f92bc5b1e119";
	// private final String APP_ID = "wx6d47db34d18f5e3a";
	// private final String PARTNER = "1494469742";
	// private final String NOTIFY_URL = "https://app.cenjiawen.com/billPush";
	// private final String PARTNER_KEY = "zhenyikejizhenyikejizhenyikejizy";
	private final boolean DEBUG = PropKit.getBoolean("devMode", false);
	// private final boolean ENABLE_PAY = PropKit.getBoolean("enablePay",
	// false);
	private final String DEBUG_PRICE = "1";
	private final Hashids hashids = new Hashids("zhenyikeji", 32);
	// private final String wechatHost = PropKit.get("wechatHost",
	// "zhenyi.cenjiawen.com");

	/**
	 * 是否第三方登录
	 */
	protected boolean IS_THIRD_LOGIN = PropKit.getBoolean("IS_THIRD_LOGIN", true);;
	/**
	 * 开放平台appid
	 */
	private final String component_appid = PropKit.get("component_appid", "wx27699ffda37093aa");

	Semaphore semaphore = new Semaphore(10);

	protected String getOpenId() {
		String openId = AuthUtils.getTokenUid(this);
		return openId;
	}

	@Clear
	public void html() {
		render("/card/index.html");
	}

	public void vue() {
		redirect("/html/#/home");
	}

	private BkApp getApp() {
		String appid = getAppid();
		BkApp app = BkApp.dao.searchFirst("appid", appid);
		return app;
	}

	// @Clear
	// public void login() {
	// BkApp app = getApp();
	// WeixinUtils weixinUtils = new WeixinUtils(app.getAppid(),
	// app.getSecret());
	// String url = "http://zhenyi.cenjiawen.com/auth";
	// String redirect = weixinUtils.generateWechatUrl(url, false);
	// System.out.println(redirect);
	// redirect(redirect);
	// }

	private void resutl(boolean flag, String pageTitle, String title, String desc, String info, String reason,
			String buttonTitle, String url) {
		setAttr("flag", flag);
		setAttr("pageTitle", pageTitle);
		setAttr("title", title);
		setAttr("desc", desc);
		setAttr("info", info);
		setAttr("reason", reason);
		setAttr("buttonTitle", buttonTitle);
		setAttr("url", url);
		render("result.html");
	}

	public void pay() {
		// PaymentApi.pushOrder(params);
	}

	@Override
	public Integer getShopId() {
		Integer shopId = defaultShopId;
		try {
			shopId = getParaToInt("shopId");
			if (shopId == null) {
				return null;
			}
		} catch (Exception e) {
			LogKit.error("shop Id error");
			return null;
		}
		// if (shopId == null) {
		// shopId = defaultShopId;
		// }
		return shopId;
	}

	public void home() {
		prepareShop();
		render("home2.html");
	}

	// public void ttt() {
	// DBMap map = new DBMap();
	// map.put("title", "title");
	// List<BkBooking> booking = BkBooking.dao.findLast(3);
	// map.put("booking", booking);
	// renderJson(map);
	// }

	private void prepareShop() {
		Integer shopId = getShopId();
		if (shopId == null) {
			return;
		}
		DBMap dbMap = new DBMap();

		List<BkShop> shops = BkShop.dao.avaliableShops(shopId);
		if (shops.size() > 0) {
			setAttr("shops", shops);
			dbMap.put("shops", shops);
		} else {
			dbMap.put("shops", new ArrayList<>());
		}

		Integer itemId = getItemId();
		Integer selectionId = getSelectionId();
		Integer time = null;
		try {
			String timeIndex = getPara("time");
			if (StrKit.notBlank(timeIndex)) {
				if (!"undefined".equals(timeIndex)) {
					time = Integer.parseInt(timeIndex);
				}
			}
		} catch (Exception e) {
			LogKit.error("parse time error", e);
		}
		String date = getPara("date");
		date = StrKit.notBlank(date) ? date : Utils.getDate();
		try {
			Long dateNumber = getParaToLong("dateNumber");
			if (dateNumber != null) {
				date = Utils.dateFromNumber(dateNumber, "yyyy-MM-dd");
			}
		} catch (Exception e) {
		}

		String itemName = "";
		String selectionName = "";

		BkShop shop = BkShop.dao.findById(shopId);
		List<BkItem> items = BkItem.dao.findAvaliableItems(shopId, date);
		if (items.size() <= 0) {
			LogKit.warn("no item");
			// renderFailure(500, "no item");
			// return;
		} else {
			if (itemId == null) {
				BkItem firstItem = items.get(0);
				itemId = firstItem.getId();
			} else {
			}
		}

		if (itemId != null) {
			itemName = BkItem.dao.findById(itemId).getName();
		}
		List<BkSelection> selections = BkSelection.dao.findByItem(itemId);
		selections = BkSelection.dao.getAvailableSelections(selections, date);
		boolean haveSelection = false;

		for (BkSelection bkSelection : selections) {
			if (bkSelection.getId() == selectionId) {
				haveSelection = true;
			}
		}
		// System.out.println("selectionId " + selectionId);
		if (selections.size() <= 0) {
			LogKit.warn("no selections");
		} else {
			if ((selectionId == null) || !haveSelection) {
				BkSelection selection = selections.get(0);
				selectionId = selection.getId();
			}
			selectionName = BkSelection.dao.findById(selectionId).getName();
		}

		dbMap.put("shop", shop);
		dbMap.put("items", items);
		dbMap.put("selections", selections);

		setAttr("itemName", itemName);
		dbMap.put("itemName", itemName);

		setAttr("selectionName", selectionName);
		dbMap.put("selectionName", selectionName);

		setAttr("realSelectionName", selectionName);
		dbMap.put("realSelectionName", selectionName);

		/**
		 * remember remove techinicianId
		 */
		BookingUtils bookingUtils = new BookingUtils(shopId);
		setAttr("shop", shop);
		dbMap.put("shop", shop);

		setAttr("items", items);
		dbMap.put("items", items);

		setAttr("selections", selections);
		dbMap.put("selections", selections);

		setAttr("itemId", itemId);
		dbMap.put("itemId", itemId);

		setAttr("selectionId", selectionId);
		dbMap.put("selectionId", selectionId);

		setAttr("shopId", shop.getId());
		dbMap.put("shopId", shopId);

		ArrayList<String> dates = bookingUtils.selectionDates();

		setAttr("dates", dates);
		dbMap.put("dates", dates);

		renderJson(dbMap);

		// getSpareTime(4, 2, itemId, bookDay)

		String bookDay = date;

		ArrayList<HashMap<String, Object>> times = bookingUtils.getTimeArray(time, selectionId, itemId, bookDay);
		if (bookingUtils.shouldAutoSelectAvailableTime()) {
			for (HashMap<String, Object> hashMap : times) {
				boolean isAvaliable = (boolean) hashMap.get("selected");
				if (isAvaliable) {
					int bookTime = (int) hashMap.get("index");
					setAttr("time", bookTime);
					dbMap.put("time", bookTime);

					String timeString = bookingUtils.timeUtil.timeIndexToString(bookTime);
					setAttr("timeString", timeString);
					dbMap.put("timeString", timeString);

				}
			}
		}
		// System.out.println("selectionId: " + selectionId + " itemId: " +
		// itemId + " bookDay: " + bookDay);
		setAttr("img", "http://oagxrzzdf.bkt.clouddn.com/tt.jpg?imageView2/1/w/50/h/50");

		ArrayList<HashMap<String, Object>> timesArray = bookingUtils.getTimeArray(time, selectionId, itemId, bookDay);
		setAttr("times", timesArray);
		dbMap.put("times", timesArray);

		Long today = Utils.todayNumber();
		setAttr("today", today);
		dbMap.put("today", today);

		setAttr("date", date);
		dbMap.put("date", date);

		String todayDate = Utils.getDate();
		setAttr("todayDate", todayDate);
		dbMap.put("todayDate", todayDate);

		render("home.html");

		Integer json = getParaToInt("json");
		if (json != null) {
		}
		renderResult(dbMap);
	}

	@Clear
	@Override
	public void index() {
		super.index();
		try {
			renderFailure();
			prepareShop();
		} catch (Exception e) {
			e.printStackTrace();
			// render("/bk/404.html");
			renderFailure();
		}
	}

	public void hhh() {
		String img = "http://res.zhen-yee.com/res/health/circle4.png";
		String html = "<img src='IMG'></img>";
		html = html.replace("IMG", img);
		renderHtml(html);
	}

	// private boolean onBook() {
	// BkBooking model = getModel(BkBooking.class);
	// int selectionId = model.getSelectionId();
	// int shopId = model.getShopId();
	// int itemId = model.getItemId();
	// String date = model.getBookDay();
	// int time = model.getBookTime();
	// BookingUtils bookingUtils = new BookingUtils(shopId);
	// ArrayList<Boolean> spareTimeArray =
	// bookingUtils.getSpareTime(selectionId, itemId, date);
	// boolean canBook = spareTimeArray.get(time);
	// return canBook;
	// }

	public void notiBookSuccess(BkBooking booking) {

	}

	// public void genBooking() {
	// List<BkBooking> books = BkBooking.dao.findAll();
	// for (BkBooking bkBooking : books) {
	// bkBooking.updateBookingTimeDouble();
	// }
	// renderSuccess();
	// }

	@Clear
	public void testing() {
		try {
			semaphore.acquire();
			renderSuccess();
			semaphore.release();
		} catch (Exception e) {
			e.printStackTrace();
			renderFailure();
		}
	}

	public void bookConfirm(BkBooking model, boolean isWeb) {
		boolean isJson = getParaToInt("json") != null;
		Integer shopId = model.getShopId();
		Integer itemId = model.getItemId();
		// 0,小程序,1.网页
		Integer mode = getParaToInt("mode");
		if (mode == null) {
			mode = 0;
		}
		BkItem bkItem = BkItem.dao.findById(itemId);
		BkShop shop = BkShop.dao.findById(shopId);
		String date = model.getBookDay();
		int time = model.getBookTime();
		// BookingUtils bookingUtils = new BookingUtils(shopId);
		// ArrayList<Boolean> spareTimeArray =
		// bookingUtils.getSpareTime(selectionId, itemId, date);
		// boolean canBook = spareTimeArray.get(time);
		boolean flag = Db.tx(new IAtom() {

			@Override
			public boolean run() throws SQLException {
				try {
					boolean flag = confirmBillOrder(model, isWeb);
					return flag;
				} catch (Exception e) {
					e.printStackTrace();
				}
				return false;
			}
		});

		if (flag) {
			// model.setDate(dateNow());
			// model.setTime(timeNow());
			// BKUtils utils = new BKUtils(model.getShopId());
			// String timeStr =
			// utils.timeUtil.timeIndexToString(model.getBookTime());
			// // // Date bookDate = DateUtils.dateFromString(date + " " +
			// timeStr,
			// // // "yyyy-MM-dd HH:mm");
			// // // model.setBookDate(bookDate);
			// // if (isJson) {
			// // // sendTemplate(openId, formId, model, bkItem.getName(),
			// // // shop.getName(), mark);
			// // // renderSuccess();
			// // // return;
			// // // model.updateIfExist();
			// // } else {
			// // }
			// // model.updateIfExist();
			// BkSelection selection =
			// BkSelection.dao.findById(model.getSelectionId());
			// String br = "<br/>";
			// String content = model.getItem().getName() + br +
			// model.getBookDay() + br + timeStr + br + "客人: "
			// + model.getName() + br + "电话: " + model.getPhone();
			// MailUtils mailUtils = MailUtils.cjwdevelop();
			// String title = selection.getName() + "的预约";
			// String email = selection.getEmail();
			// if (isEmail(email)) {
			// email = "frank@cenjiawen.com";
			// boolean emailFlag = mailUtils.sendMail(title, content, email,
			// "moomi");
			// // if (!emailFlag) {
			// // mailUtils.sendMail(title + " 失败", content,
			// // "frank@cenjiawen.com", "moomi");
			// // }
			// }
			// model.sendEmail();
			if (isJson || mode == 1 || isWeb) {
				renderSuccess();
				// sendTemplate(openId, formId, nickName, mobile, bookDay,
				// "目美项目", "目美店", "预约小程序测试", shopId);
				// sendTemplate(openId, formId, model, bkItem.getName(),
				// shop.getName(), mark);
			} else {
				resutl(true, "预约成功", "稍后会有工作人员与您联系", "", "", "", "确定", "index?shopId=" + shopId);
				renderMsg("预约成功");
			}
		} else {
			if (isJson || mode == 1) {
				renderMsg("预约时间冲突");
			} else {
				resutl(false, "预约失败", "预约时间冲突", "请重新预约", "", "", "确定", "index?shopId=" + shopId);
				renderMsg("预约时间冲突");
			}
		}
		// resutl(canBook);
	}

	private Map<String, Object> getSessionKey(String appid, String secret, String code) {
		String url = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";
		url = url.replace("APPID", appid);
		url = url.replace("SECRET", secret);
		url = url.replace("JSCODE", code);
		String response = HttpKit.get(url);
		@SuppressWarnings("unchecked")
		Map<String, Object> info = Utils.jsonToMap(response);
		return info;
	}

	private String getToken(BkApp app) {
		Cache cache = Redis.use();
		String key = "xcxToken";
		String accessToken = cache.get(key);
		if (accessToken == null) {
			String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
			url = url.replace("APPSECRET", app.getSecret());
			url = url.replace("APPID", app.getAppid());
			String json = HttpKit.get(url);
			Map<String, Object> result = Utils.jsonToMap(json);
			String access_token = (String) result.get("access_token");
			// String expires_in = (String) result.get("access_token");
			cache.setex(key, 300, access_token);
			return access_token;
		} else {
			return accessToken;
		}
	}

	private boolean canBook(Integer shopId, Integer selectionId, Integer itemId, String date, int bookTime) {
		BookingUtils bookingUtils = new BookingUtils(shopId);
		ArrayList<Boolean> spareTimeArray = bookingUtils.getSpareTime(selectionId, itemId, date);
		boolean canBook = spareTimeArray.get(bookTime);
		return canBook;
		// return false;
	}

	private void sendTemplate(String openId, String formId, BkBooking model, String title, String address,
			String mark) {
		if (formId != null && !"the formId is a mock one".equals(formId)) {
			sendTemplate(openId, formId, model.getName(), model.getPhone(), model.getBookDay(), title, address, mark,
					model.getShopId());
		} else {
			if (DEBUG) {
				LogKit.warn("no formId");
			}
		}
	}

	@Clear(BKInterceptor.class)
	public void requstBooking() {
		try {
			Integer itemId = getParaToInt("itemId");
			/**
			 * 是否由web提交
			 */
			boolean isWeb = getParaToInt("isWeb") != null;
			BkItem item = BkItem.dao.findById(itemId);
			Integer price = item.getPrice();
			if (DEBUG) {
				price = 1;
			}
			String mobile = getPara("mobile");
			String bookDay = getPara("bookDay");
			String nickName = getPara("nickName");
			String openId = getOpenId();
			if (isWeb) {
				openId = null;
			}
			String formId = getPara("formId");
			String mark = getPara("mark");
			Integer selectionId = getParaToInt("selectionId");
			Integer shopId = getParaToInt("shopId");
			String selectedTime = getPara("selectedTime");
			BkShop shop = BkShop.dao.findById(shopId);
			BkBooking model = new BkBooking();
			if (StrKit.isBlank(mark)) {
				if (DEBUG) {
					mark = "预约小程序测试";
				}
			}
			model.setName(nickName);
			model.setRemark(mark);
			model.setPhone(mobile);
			model.setBookDay(bookDay);
			model.setBookTime(getParaToInt("bookTime"));
			model.setShopId(shopId);
			model.setSelectionId(selectionId);
			model.setOpenId(openId);
			model.setItemId(itemId);
			model.setStatus(-2);
			model.setDate(dateNow());
			model.setTime(timeNow());
			model.setFormId(formId);
			model.setBookDate(DateUtils.dateFromString(bookDay + " " + selectedTime, DateUtils.YYYYMMDD_HHMM));
			model.save();
			boolean enablePay = shop.getNeedPay() != null;
			// LogKit.info("enablePay: " + enablePay);
			// model.updateBookingTimeDouble();
			if (price != null && price > 0 && enablePay) {
				String total = price * 100 + "";
				if (DEBUG) {
					total = DEBUG_PRICE;
				}
				BkApp app = getApp();
				BkOrder order = new BkOrder();
				order.setAddTime();
				order.setOpenid(openId);
				order.setTotalFee(total);
				order.setPrice(Integer.parseInt(total));
				order.setAppId(app.getAppid());
				order.setMchId(app.getPartner());
				order.setTotalFee(total);
				order.setShopId(shopId);
				// order.setPrepayId(prepayId);
				order.setStatus(0);
				order.save();
				model.setShouldPay(1);
				model.setOrderId(order.getId());
				model.update();
				paySubmit(order, model);
			} else {
				bookConfirm(model, isWeb);
			}
		} catch (Exception e) {
			LogKit.error("request booking error", e);
			renderFailure();
		}
	}

	private String getAppid() {
		return getPara("appid");
	}

	public void paySubmit(BkOrder order, BkBooking model) {
		boolean isJson = getParaToInt("json") != null;
		String orderNo = hashids.encode(order.getId());
		order.setOutTradeNo(orderNo);
		String nonce_str = System.currentTimeMillis() / 1000 + "";

		// String prefix = DEBUG ? "debug" : "zy";
		String tradeNo = orderNo;
		// String openId = getPara("openId");// "oAngF0VdBpU29x7T8-CVP68QCXIw";
		Map<String, String> params = new HashMap<String, String>();

		BkApp app = BkApp.dao.searchFirst("appid", getAppid());
		params.put("appid", app.getAppid());
		params.put("mch_id", app.getPartner());
		params.put("body", "微信支付");
		params.put("out_trade_no", tradeNo);
		params.put("total_fee", "" + order.getTotalFee());
		params.put("attach", "" + model.getShopId());
		String ip = IpKit.getRealIp(getRequest());
		if (StrKit.isBlank(ip)) {
			ip = "127.0.0.1";
		}
		if (DEBUG) {
			ip = "127.0.0.1";
		}
		params.put("spbill_create_ip", ip);
		params.put("trade_type", TradeType.JSAPI.name());
		params.put("nonce_str", nonce_str);
		params.put("notify_url", app.getNofityUrl());
		params.put("openid", order.getOpenid());
		String sign = PaymentKit.createSign(params, app.getPartnetKey());
		params.put("sign", sign);
		String xmlResult = PaymentApi.pushOrder(params);
		Map<String, String> result = PaymentKit.xmlToMap(xmlResult);
		if (!PayUtils.isXMLSuccess(result)) {
			if (DEBUG) {
				LogKit.warn(xmlResult);
			}
			LogKit.error("pay error " + xmlResult);
			renderFailure("支付失败");
			return;
		}

		String prepay_id = result.get("prepay_id");
		DateTime dateTime = new DateTime();
		String timeStamp = dateTime.toDate().getTime() / 1000 + "";
		String signString = "appId=" + app.getAppid() + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id
				+ "&signType=MD5&timeStamp=" + timeStamp + "&key=" + app.getPartnetKey();
		signString = HashKit.md5(signString).toUpperCase();
		DBMap map = new DBMap();
		map.put("result", result);
		map.put("sign", signString);
		map.put("timeStamp", timeStamp);
		map.put("nonce_str", nonce_str);
		order.setPrepayId(prepay_id);
		order.update();
		renderResult(map, "pay", 201);
		// renderJson(map);
	}

	@Clear
	@Before(TestInterceptor.class)
	public void query() {
		String no = getPara("no");
		if (StrKit.isBlank(no)) {
			renderFailure();
		}
		String out_trade_no = no;
		long id = hashids.decode(out_trade_no)[0];
		BkOrder order = BkOrder.dao.findById(id);
		renderJson(order.query());
	}

	@Clear
	@Before(TestInterceptor.class)
	public void refund() {
		String no = getPara("no");
		if (StrKit.isBlank(no)) {
			renderFailure();
			Integer orderId = getParaToInt("orderId");
			BkOrder order = BkOrder.dao.findById(orderId);
			order.refund(order.getTotalFee());
			renderSuccess();
			return;
		}
		try {
			String out_trade_no = no;
			long id = hashids.decode(out_trade_no)[0];
			BkOrder order = BkOrder.dao.findById(id);
			order.refund(order.getTotalFee());
			renderSuccess();
		} catch (Exception e) {
			renderFailure();
		}
	}

	private boolean confirmBillOrder(BkBooking booking, boolean isWebSubmit) {
		if (canBook(booking.getShopId(), booking.getSelectionId(), booking.getItemId(), booking.getBookDay(),
				booking.getBookTime()) || isWebSubmit) {
			BkBooking model = booking;
			model.setStatus(0);
			model.setDate(dateNow());
			model.setTime(timeNow());
			model.updateIfExist();
			// model.updateBookingTimeDouble();

			String openId = model.getOpenId();
			String formId = model.getFormId();
			BkItem bkItem = BkItem.dao.findById(model.getItemId());
			BkShop shop = BkShop.dao.findById(model.getShopId());
			String mark = model.getRemark();
			sendTemplate(openId, formId, model, bkItem.getName(), shop.getAddress(), mark);
			model.sendEmail();
			return true;
		}
		return false;
	}

	public boolean confirmBillOrder(BkOrder order, boolean isWeb) {
		BkBooking booking = BkBooking.dao.searchFirst("orderId", order.getId());
		booking.setIsPaid(1);
		booking.update();
		if (confirmBillOrder(booking, isWeb)) {
			return true;
		} else {
			order.refund(order.getTotalFee());
			LogKit.warn("预约失败,立即退款");
			return false;
		}
	}

	@Clear
	public void billPush() {
		try {
			String xmlResult = HttpKit.readData(getRequest());
			Map<String, String> result = PaymentKit.xmlToMap(xmlResult);
			String appid = result.get("appid");
			String bank_type = result.get("bank_type");
			String cash_fee = result.get("cash_fee");
			String fee_type = result.get("fee_type");
			String is_subscribe = result.get("is_subscribe");
			String mch_id = result.get("mch_id");
			String nonce_str = result.get("nonce_str");
			String openid = result.get("openid");
			String out_trade_no = result.get("out_trade_no");
			String result_code = result.get("result_code");
			String return_code = result.get("return_code");
			String sign = result.get("sign");
			String time_end = result.get("time_end");
			String total_fee = result.get("total_fee");
			String trade_type = result.get("trade_type");
			String transaction_id = result.get("transaction_id");
			String attach = result.get("attach");
			// System.out.println(JsonKit.toJson(result));
			// System.out.println("--------");
			// System.out.println(JsonKit.toJson(result));
			// System.out.println("out_trade_no: " + out_trade_no);
			// System.out.println("total_fee: " + total_fee);
			// System.out.println("cash_fee: " + cash_fee);
			// System.out.println("out_trade_no: " + out_trade_no);
			// System.out.println("--------");

			long id = hashids.decode(out_trade_no)[0];
			BkOrder order = BkOrder.dao.findById(id);
			order.setBankType(bank_type);
			order.setIsSubscribe(is_subscribe);
			order.setTradeType(trade_type);
			order.setTransactionId(transaction_id);
			order.setFeeType(fee_type);
			order.setTimeEnd(time_end);
			order.setCashFee(cash_fee);
			order.setPaid(Integer.parseInt(total_fee));
			order.setAttach(attach);
			order.update();

			order.updateOrderStatus();

			if (order.getStatus().equals(1)) {
				new Thread(new Runnable() {
					@Override
					public void run() {
						confirmBillOrder(order, false);
					}
				}).start();
			}
			// if (PropKit.getBoolean("devMode", false)) {
			// Thread.sleep(3000);
			// boolean flag = order.refund(total_fee);
			// System.out.println("refund " + flag);
			// // String refundNo = "debug" + new Date().getTime();
			// // Map<?, ?> refund = payUtils.refundOrderNo(out_trade_no,
			// // cash_fee, cash_fee, refundNo);
			// // System.out.println(JsonKit.toJson(refund));
			// }
		} catch (Exception e) {
			LogKit.error("bill push error", e);
		}
		String returnXML = "<xml>\n" + "<return_code><![CDATA[SUCCESS]]></return_code>\n"
				+ "<return_msg><![CDATA[OK]]></return_msg>\n" + "</xml>";
		renderText(returnXML, "text/xml");
	}

	// private PayUtils payUtils = PayUtils.instance();
	@Clear
	public void init() {
		Integer shopId = getParaToInt("shopId");
		BkShop shop = BkShop.dao.findById(shopId);
		renderResult(shop);
	}

	// private void sendTemplate(BkBooking booking) {
	// BkShop shop = BkShop.dao.findById(booking.getShopId());
	// sendTemplate(booking.getOpenId(), booking.getFormId(), booking, "",
	// shop.getAddress(), booking.getRemark());
	// }

	/**
	 * 发送预约成功模板消息
	 * 
	 * @param openId
	 * @param formId
	 * @param name
	 * @param mobile
	 * @param bookDay
	 * @param title
	 * @param address
	 * @param mark
	 * @param shopId
	 */
	private void sendTemplate(String openId, String formId, String name, String mobile, String bookDay, String title,
			String address, String mark, int shopId) {
		if (formId.equals("the formId is a mock one")) {
			return;
		}
		BkShop shop = BkShop.dao.findById(shopId);
		BkApp app = BkApp.dao.findById(shop.getApp());
		String token = getToken(app);
		String template_id = "MojKRH0xE7oUL58iE7Fn8MCLv44h4H_aJRquSLVpR-w";
		DBMap map = new DBMap();
		map.put("touser", openId);
		map.put("template_id", template_id);
		map.put("form_id", formId);
		map.put("page", "pages/index/index?shopId=" + shopId + "&appid=" + app.getAppid());

		DBMap data = new DBMap();

		DBMap keyword1 = new DBMap();
		keyword1.put("value", name);
		DBMap keyword2 = new DBMap();
		keyword2.put("value", mobile);
		DBMap keyword3 = new DBMap();
		keyword3.put("value", title);
		DBMap keyword4 = new DBMap();
		keyword4.put("value", bookDay);
		DBMap keyword5 = new DBMap();
		keyword5.put("value", address);
		DBMap keyword6 = new DBMap();
		keyword6.put("value", mark);

		data.put("keyword1", keyword1);
		data.put("keyword2", keyword2);
		data.put("keyword3", keyword3);
		data.put("keyword4", keyword4);
		data.put("keyword5", keyword5);
		data.put("keyword6", keyword6);

		map.put("data", data);

		String url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN";
		url = url.replace("ACCESS_TOKEN", token);
		String result = HttpKit.post(url, JsonKit.toJson(map));
	}

	/**
	 * 我的预定
	 */
	public void mybooking() {
		String openId = getOpenId();
		// if (StrKit.isBlank(openId)) {
		// openId = getPara("openId");
		// // renderFailure("error open Id");
		// // return;
		// }
		// Integer shopId = getParaToInt("shopId");
		List<BkBooking> items = BkBooking.dao.find(Db.getSql("MyBooking"), openId);
		renderResult(items);
	}

	/**
	 * 全部预约
	 */
	public void allbooking() {
		Integer shopId = getParaToInt("shopId");
		List<BkBooking> items = BkBooking.dao.find(Db.getSql("AllBooking"), shopId);
		renderResult(items);
	}

	/**
	 * 取消订单
	 */
	public void cancel() {
		Integer id = getParaToInt("id");
		Integer shopId = getParaToInt("shopId");
		BkBooking bkBooking = BkBooking.dao.findById(id);
		if (!shopId.equals(bkBooking.getShopId())) {
			renderFailure();
			return;
		}
		boolean canCancel = true;
		Date now = new Date();
		if (bkBooking.getBookDate().getTime() - now.getTime() <= 7200000) {
			canCancel = false;
		}
		if (!canCancel) {
			renderMsg("需要提前2小时取消");
			return;
		}
		bkBooking.setStatus(-1);
		boolean flag = bkBooking.update();
		renderFlag(flag);
		// renderMsg("暂不支持取消");
	}

	private JSONObject thirdLogin(String appid, String code) {
		// Cache cache = Redis.use();
		// String url =
		// "https://api.weixin.qq.com/sns/component/jscode2session?"
		// +
		// "appid={}&js_code={}&grant_type=authorization_code&component_appid={}&component_access_token={}";
		// String component_access_token = cache.get("component_access_token");
		// url = StrFormatter.format(url, appid, code, component_appid,
		// component_access_token);
		// String response = HttpUtil.get(url);
		// JSONObject jsonObject = new JSONObject(response);
		// return jsonObject;
		WXThirdUtils thirdUtils = new WXThirdUtils(component_appid);
		return thirdUtils.thirdLogin(appid, code);
	}

	@Clear
	public void userInfo() {
		try {
			String iv = getPara("iv");
			String code = getPara("code");
			String encryptedData = getPara("encryptedData");
			String appid = getAppid();
			if (StrKit.isBlank(appid)) {
				renderFailure("not appid");
				return;
			}
			BkApp app = getApp();
			String session_key = "";
			String openId = "";
			if (IS_THIRD_LOGIN) {
				JSONObject jsonObject = thirdLogin(app.getAppid(), code);
				session_key = jsonObject.getStr("session_key");
				openId = jsonObject.getStr("openid");
				// String unionid = jsonObject.getStr("unionid");
			} else {
				Map<String, Object> info = getSessionKey(app.getAppid(), app.getSecret(), code);
				session_key = (String) info.get("session_key");
				openId = (String) info.get("openid");
			}
			if (!StrKit.notBlank(session_key, openId)) {
				renderFailure("login error");
				return;
			}

			String json = AES.de(encryptedData, session_key, iv);
			Map<String, Object> userInfo = Utils.jsonToMap(json);
			String nickName = (String) userInfo.get("nickName");
			Integer gender = (Integer) userInfo.get("gender");
			String language = (String) userInfo.get("language");
			String city = (String) userInfo.get("city");
			String province = (String) userInfo.get("province");
			String country = (String) userInfo.get("country");
			String avatarUrl = (String) userInfo.get("avatarUrl");
			// BkWechat wechat = BkWechat.dao.searchFirst("openId", openId);
			BkWechat wechat = BkWechat.dao.findByOpenId(openId);
			if (wechat == null || wechat.getOpenId() == null) {
				wechat = new BkWechat();
				wechat.setOpenId(openId);
				wechat.setAddTime();
				wechat.save();
			}
			wechat.setSessionKey(session_key);
			wechat.setAppid(appid);
			if (StrKit.notBlank(nickName)) {
				wechat.setNickName(nickName);
			}
			if (gender != null) {
				wechat.setGender(gender);
			}
			if (StrKit.notBlank(language)) {
				wechat.setLanguage(language);
			}
			if (StrKit.notBlank(city)) {
				wechat.setCity(city);
			}
			if (StrKit.notBlank(province)) {
				wechat.setProvince(province);
			}
			if (StrKit.notBlank(country)) {
				wechat.setCountry(country);
			}
			if (StrKit.notBlank(avatarUrl)) {
				wechat.setAvatarUrl(avatarUrl);
			}
			wechat.update();
			String token = AuthUtils.login(wechat.getOpenId());
			DBMap map = new DBMap();
			map.put("openId", openId);
			map.put("token", token);
			renderResult(map);
		} catch (Exception e) {
			LogKit.error("userinfo error", e);
			renderFailure();
		}
	}

	public void mobile() {
		String openId = getOpenId();
		BkWechat wechat = BkWechat.dao.findByOpenId(openId);
		if (wechat == null) {
			renderFailure("获取用户失败");
			return;
		} else {
		}

		String iv = getPara("iv");
		String encryptedData = getPara("encryptedData");
		String json = AES.de(encryptedData, wechat.getSessionKey(), iv);
		JSONObject jsonObject = new JSONObject(json);
		String mobile = jsonObject.getStr("phoneNumber", "");
		renderResult(mobile);
	}

	@Clear
	public void adv() {
		// int shopId = getParaToInt("shopId");
		List<BkAdv> items = BkAdv.dao.findAll();
		renderResult(items);
	}

}
